package com.ycl.javacore.rpctest.registry;

import com.alibaba.fastjson.JSONArray;
import com.ycl.javacore.rpctest.common.InvokeUtils;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;

import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * User: OF1089 杨成龙
 * Date: 2019/8/23
 * Time: 4:00 PM
 * Desc: 类描述
 */
public class ZookeeperRegistry implements Registry {

    private String registryUrl;
    private CuratorFramework client;

    public ZookeeperRegistry(String registryUrl) {
        this.registryUrl = registryUrl;

        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
        client = CuratorFrameworkFactory.newClient(registryUrl, retryPolicy);
        client.start();

        try {
            Stat myRPC = client.checkExists().forPath("/myRPC");
            if (myRPC == null) {
                client.create()
                        .creatingParentsIfNeeded()
                        .forPath("/myRPC");
            }
            System.out.println("Zookeeper Client初始化完毕");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @Override
    public void register(Class clazz, RegistryInfo registryInfo) throws Exception {
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            String key = InvokeUtils.buildInterfaceMethodIdentify(clazz, method);
            String path = "/myRPC/" + key;
            Stat stat = client.checkExists().forPath(path);
            List<RegistryInfo> registryInfoList;
            //!=null说明已经被被的机器写过数据了，注册的机器可能有多个
            if (stat != null) {
                byte[] bytes = client.getData().forPath(path);
                String data = new String(bytes, StandardCharsets.UTF_8);
                registryInfoList = JSONArray.parseArray(data, RegistryInfo.class);
                if (registryInfoList.contains(registryInfo)) {
                    System.out.println("地址列表已经包含了本机【" + key + "】，不注册了");
                } else {
                    registryInfoList.add(registryInfo);
                    client.setData().forPath(path, JSONArray.toJSONString(registryInfoList).getBytes());
                    System.out.println("注册到注册中心，路径为：【" + path + "】信息为：" + registryInfo);
                }
            } else {
                registryInfoList = new ArrayList<>();
                registryInfoList.add(registryInfo);

                client.create()
                        .creatingParentsIfNeeded()
                        .withMode(CreateMode.EPHEMERAL)
                        .forPath(path, JSONArray.toJSONString(registryInfoList).getBytes());
                System.out.println("注册到注册中心，路径为：【" + path + "】信息为：" + registryInfo);
            }
        }
    }

    @Override
    public List<RegistryInfo> fetchRegistry(Class clazz) throws Exception {
        Method[] declareMethods = clazz.getDeclaredMethods();
        List registryInfoList = null;
        for (Method method : declareMethods) {
            String key = InvokeUtils.buildInterfaceMethodIdentify(clazz, method);
            String path = "/myRPC/" + key;
            Stat stat = client.checkExists().forPath(path);
            if (stat == null) {
                // 这里可以添加watcher来监听变化，这里简化了，没有做这个事情
                System.out.println("警告：无法找到服务接口：" + path);
                continue;
            }
            if (registryInfoList == null) {
                byte[] bytes = client.getData().forPath(path);
                String data = new String(bytes, StandardCharsets.UTF_8);
                registryInfoList = JSONArray.parseArray(data, RegistryInfo.class);
            }
        }
        return registryInfoList;
    }
}
